package main

import (
	"flag"
	"fmt"
	"gotool/gotool/systemtool"
	"sync"
	"time"

	"github.com/guptarohit/asciigraph"
)

var (
	// 数据显示y轴粒度
	Height int
	// 获取次数
	Count int
	// 获取数据频率,单位ms
	Interval int
	// 是否获取CPU数据
	GetCpu bool
	// 是否获取内存数据
	GetMem bool
)

func initFlag() {
	flag.BoolVar(&GetCpu, "c", true, "是否获取cpu信息")
	flag.BoolVar(&GetMem, "m", true, "是否获取内存信息")
	flag.IntVar(&Height, "y", 10, "y轴粒度")
	// flag.IntVar(&Width, "w", 0, "x轴粒度")
	flag.IntVar(&Count, "n", 10, "获取n次数据")
	flag.IntVar(&Interval, "s", 500, "获取频率,单位ms")
	flag.Parse()
}

type SystemTask interface {
	// 获取数据方法
	Task()
	// 显示数据方法
	PrintData()
}

// 编译期间检查是否实现了SystemTask接口
var _ SystemTask = &CPU{}
var _ SystemTask = &MEM{}

type MEM struct {
	Data []float64
}

func NewMEM() *MEM {
	data := make([]float64, 0)
	return &MEM{Data: data}
}

type CPU struct {
	Data []float64
}

func NewCPU() *CPU {
	data := make([]float64, 0)
	return &CPU{Data: data}
}

func (c *CPU) Task() {
	usage, err := systemtool.GetCpu(Interval)
	if err != nil {
		return
	}
	c.Data = append(c.Data, usage...)
}

func (c *CPU) PrintData() {
	fmt.Println("**********CPU使用率**********")
	fmt.Println(asciigraph.Plot(c.Data, asciigraph.Width(0), asciigraph.Height(Height)))
}

func (mem *MEM) Task() {
	v, err := systemtool.GetMem()
	if err != nil {
		return
	}
	mem.Data = append(mem.Data, v.UsedPercent)
	// fmt.Println("mem task...")
}

func (mem *MEM) PrintData() {
	fmt.Println("**********内存使用率**********")
	fmt.Println(asciigraph.Plot(mem.Data, asciigraph.Width(0), asciigraph.Height(Height)))
}

func main() {
	initFlag()
	uiStart()
}

var wg sync.WaitGroup

func uiStart() {

	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("r: %v\n", r)
		}
	}()

	// SystemTask接口已经是一个指针类型,无法再定义*SystemTask
	//
	// 永远不要使用一个指针指向一个接口类型，因为它已经是一个指针。
	var sys []SystemTask

	// 按顺序初始化任务
	if GetCpu {
		c := NewCPU()
		sys = append(sys, c)
	}

	if GetMem {
		m := NewMEM()
		sys = append(sys, m)
	}

	delta := len(sys)

	for ix := 0; ix < Count; ix++ {
		wg.Add(delta)

		for _, task := range sys {

			// 使用闭包方式避免for range坑
			go func(sysT SystemTask) {
				defer func() {
					if r := recover(); r != nil {
						fmt.Println(r)
					}
				}()
				defer wg.Done()
				sysT.Task()
			}(task)
		}

		wg.Wait()

		// 清屏
		fmt.Printf("\033[1J")
		// 按顺序显示数据
		for _, val := range sys {
			// 使用临时变量方式避免for range坑
			sysT := val
			sysT.PrintData()
		}

		// cpu自带Interval,如果不获取cpu,内存信息每隔Interval毫秒获取一次
		if !GetCpu {
			time.Sleep(time.Millisecond * time.Duration(Interval))
		}

	}

}
